package com.edol.painting.painting;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;

import com.doodle.common.utils.Utils;
import com.edol.painting.R;
import com.edol.painting.utils.PainterUtils;

public class WaterColorBrush extends TextureBrush {
	
	private Paint mDepthPaint;
	private float mDrawRadius;
	private int mDirectRadius;
	
	public WaterColorBrush(Context context) {
		super(context, BRUSH_WATERCOLOR);
		loadBrush(R.raw.watercolor);
		mDepthPaint = new Paint();
		mDepthPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
	}

	@Override
	public void setWidth(int width) {
		super.setWidth(width);
		mDrawRadius = mWidth * 2.0f + Math.round(mWidth * mDitherFactor);
	}
	
	@Override
	protected void drawParticle(Canvas canvas, Particle particle, Rect bounds) {
		float x = particle.x;
		float y = particle.y;
		int randNum = PainterUtils.getRandNum(mCurParticleIndex);
		mPaint.setAlpha(particle.alpha);
		if (DITHER_TYPE_RANDOM == mDitherType) {
			int ditherValue = randNum % mDitherRadius;
			x += ditherValue;
			y += ditherValue;
		}
		float width = particle.width;
		float startX = x - width;
		float startY = y - width;

		if (DIRECTION_TYPE_RANDOM == mDirectionType) {
			int degree = randNum % mDirectRadius;
			mMatrix.setRotate(degree, mWidth, mWidth);
			mMatrix.postScale((width * 2 + 1)/ (float)mMaskWidth, (width * 2 + 1) / (float)mMaskWidth);
		} else if (DIRECTION_TYPE_TANGENT == mDirectionType) {
			int degree = (int)particle.angle;
			mMatrix.setRotate(degree, mWidth, mWidth);
			mMatrix.postScale((width * 2 + 1)/ (float)mMaskWidth, (width * 2 + 1) / (float)mMaskWidth);
		} else if (DIRECTION_TYPE_TANGENT_RANDOM == mDirectionType) {
			int degree = (int) (particle.angle + randNum % mDirectRadius);
			mMatrix.setRotate(degree, mWidth, mWidth);
			mMatrix.postScale((width * 2 + 1)/ (float)mMaskWidth, (width * 2 + 1) / (float)mMaskWidth);
		} else {
			mMatrix.setScale((width * 2 + 1)/ (float)mMaskWidth, (width * 2 + 1) / (float)mMaskWidth);
		}
		mMatrix.postTranslate(startX, startY);
		bounds.union((int)(x - mDrawRadius), (int)(y - mDrawRadius), (int)(x + mDrawRadius), (int)(y + mDrawRadius));
        try {
            mLayerCanvas.save(Canvas.CLIP_SAVE_FLAG);
            mLayerCanvas.clipRect(bounds);
            mLayerCanvas.drawBitmap(mMask, mMatrix, mDepthPaint);
            mLayerCanvas.restore();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
		++mCurParticleIndex;
	}

	@Override
	public void drawRoute(Canvas canvas, Particle particle, Rect bounds) {
		if (canvas != null && particle != null && bounds != null && mLayer != null && mLayerCanvas != null) {
			mRoute.add(particle);
			int count = mRoute.size();
			if (count < 2) {
				return;
			}
			Route result = null;
			if (count == 2) {
				Particle p0 = mRoute.get(0);
				Particle p1 = mRoute.get(1);
				if (mEffectType == EFFECT_TYPE_PRESSURE) {
					p1.width = Utils.clamp(p0.width + mWidth * WIDTH_SCALE_FACTOR, 0, mWidth);
					p1.alpha = mAlpha;
				} else if (mEffectType == EFFECT_TYPE_FADE) {
					p1.width = mWidth;
					p1.alpha = 0;
				} else if (mEffectType == EFFECT_TYPE_PRESSURE_FADE) {
					p1.width = Utils.clamp(p0.width + mWidth * WIDTH_SCALE_FACTOR, 0, mWidth);
					p1.alpha = 0;
				} else if (mEffectType == EFFECT_TYPE_LIGHT_FADE) {
					p1.width = mWidth;
					p1.alpha = mAlpha * 2 / 3;
				} else if (mEffectType == EFFECT_TYPE_LIGHT_PRESSURE_FADE) {
					p1.width = Utils.clamp(p0.width + mWidth * WIDTH_SCALE_FACTOR, 0, mWidth);
					p1.alpha = mAlpha * 2 / 3;
				} else {
					p1.width = mWidth;
					p1.alpha = mAlpha;
				}
				Particle midPoint = Particle.getMidPoint(p0, p1);
				result = Route.calculateLinePoints(p0, midPoint, mStep);
			} else {
				Particle p0 = mRoute.get(count - 3);
				Particle p1 = mRoute.get(count - 2);
				Particle p2 = mRoute.get(count - 1);
				
				if (mEffectType == EFFECT_TYPE_PRESSURE) {
					p2.width = Utils.clamp(p1.width + mWidth * WIDTH_SCALE_FACTOR, 0, mWidth);
				} else if (mEffectType == EFFECT_TYPE_FADE) {
					p2.width = mWidth;
				} else if (mEffectType == EFFECT_TYPE_PRESSURE_FADE) {
					p2.width = Utils.clamp(p1.width + mWidth * WIDTH_SCALE_FACTOR, 0, mWidth);
				} else if (mEffectType == EFFECT_TYPE_LIGHT_PRESSURE_FADE) {
					p2.width = Utils.clamp(p1.width + mWidth * WIDTH_SCALE_FACTOR, 0, mWidth);
				} else {
					p2.width = mWidth;
				}
				p2.alpha = mAlpha;
				result = Route.calculateSmoothLinePoints(p0, p1, p2, mStep);
			}
			mDirectRadius = Math.max(1, mDirectionValue * mWidth / mMaskWidth); 
			mCurParticleIndex = 0;
			doDraw(canvas, result, bounds);
		}
	}

	@Override
	public void endRoute(Canvas canvas, Particle particle, Rect bounds) {
		if (canvas != null && particle != null && bounds != null && mLayer != null && mLayerCanvas != null) {
			mRoute.add(particle);
			if (canvas != null && mRoute != null) {
				int count = mRoute.size();
				if (count >= Route.ROUTE_BEGIN_INDEX) {
					Particle p0 = mRoute.get(count - 3);
					Particle p1 = mRoute.get(count - 2);
					Particle p2 = mRoute.get(count - 1);
					if (mEffectType == EFFECT_TYPE_PRESSURE) {
						p2.width = -p1.width;
						p2.alpha = mAlpha;
					} else if (mEffectType == EFFECT_TYPE_FADE) {
						p2.width = mWidth;
						p1.alpha = p0.alpha / 2;
						p2.alpha = -p1.alpha;
					} else if (mEffectType == EFFECT_TYPE_PRESSURE_FADE) {
						p2.width = -p1.width;
						p1.alpha = p0.alpha / 2;
						p2.alpha = -p1.alpha;
					} else if (mEffectType == EFFECT_TYPE_LIGHT_FADE) {
						p2.width = mWidth;
						p1.alpha = p0.alpha / 2;
						p2.alpha = 0;
					} else if (mEffectType == EFFECT_TYPE_LIGHT_PRESSURE_FADE) {
						p2.width = -p1.width;
						p1.alpha = p0.alpha / 2;
						p2.alpha = 0;
					} else {
						p2.width = mWidth;
						p2.alpha = mAlpha;
					}
					Route result = Route.calculateSmoothLinePoints(p0, p1, p2, mStep);
					mDirectRadius = Math.max(1, mDirectionValue * mWidth / mMaskWidth); 
					mCurParticleIndex = 0;
					doDraw(canvas, result, bounds);
				}
			}
		}
		mRoute.clear();
	}

	@Override
	protected void doDraw(Canvas canvas, Route result, Rect bounds) {
		mBounds.setEmpty();
		for (Particle p : result) {
			drawParticle(canvas, p, mBounds);
		}
		if (!mBounds.isEmpty()) {
			mLayerCanvas.save(Canvas.CLIP_SAVE_FLAG);
			mLayerCanvas.clipRect(mBounds);
			mLayerCanvas.drawColor(mColor, PorterDuff.Mode.SRC_ATOP);
			mLayerCanvas.restore();
			bounds.union(mBounds);
		}
	}
}
